/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package assignment1;

import java.io.*;
import java.util.StringTokenizer;
import java.util.Vector;
/**
 *
 * @author cjaramillo
 */
public class ExpertSystem {
    private int m_columns;
    private int m_rows;
    private Board m_terrainBoard;
    private Board m_discoveredTerrainBoard;
    private Rover m_rover;
    private InferenceEngine m_inferenceEngine;
    private Knowledgebase m_knowledgebase;
    private Database m_database;
    private String m_outputFile;
    
    ExpertSystem(String inputEnvironmentFilename, String outputLogFile) throws IOException
    {
        m_outputFile = outputLogFile;
        AssignmentFiles files = new AssignmentFiles();
        Vector<String>fileLines = files.readFileToVector(inputEnvironmentFilename);
        this.processFileContents(fileLines);
        this.setupDatabase();
        this.setupKnowledgebase();
        this.setupInferenceEngine();
    }
    
    ExpertSystem()
    {
        m_outputFile = null;
    }
    
    private void processFileContents(Vector<String>fileLines)
    {
        this.setRowsColumns(fileLines.elementAt(0));
        this.setupBoards(fileLines);
        this.setupRover(fileLines.elementAt(1));
        this.setupTarget(fileLines.elementAt(2));
    }
    
    private void setupTarget(String targetLocationfileLine)
    {
        StringTokenizer tokenizer = new StringTokenizer(targetLocationfileLine, ",");
        int column = Integer.parseInt(tokenizer.nextToken());
        int row = Integer.parseInt(tokenizer.nextToken());
        m_terrainBoard.setTarget(row,column);
        m_discoveredTerrainBoard.setTarget(row,column);
    }
    
    private void setupRover(String roverInfo)
    {
        StringTokenizer tokenizer = new StringTokenizer(roverInfo, ",");
        int column = Integer.parseInt(tokenizer.nextToken());
        int row = Integer.parseInt(tokenizer.nextToken());
        int orientation = Integer.parseInt(tokenizer.nextToken());
        m_rover = new Rover();
        m_rover.setup(column, row, orientation);
        m_terrainBoard.rover(m_rover);
        m_discoveredTerrainBoard.rover(m_rover);
        
        m_rover.setFullTerrainBoard(m_terrainBoard);
        m_rover.setDiscoveredBoard(m_discoveredTerrainBoard);
    }
    
    private void setRowsColumns(String rowsColumnLine)
    {
        StringTokenizer tokenizer = new StringTokenizer(rowsColumnLine, ",");
        m_rows = Integer.parseInt(tokenizer.nextToken());
        m_columns = Integer.parseInt(tokenizer.nextToken());
    }
    
    private void setupBoards(Vector<String>fileLines)
    {
        m_terrainBoard = new Board(m_rows, m_columns);
        m_terrainBoard.clearBoard();
        m_terrainBoard.setRandomTerrain(fileLines);

        m_discoveredTerrainBoard = new Board(m_rows, m_columns);   
    }
    
    public void run() throws IOException
    {
        this.solve();
    }
    private void solve() throws IOException
    {
        //Solve the board
        //let the rover take initial sensor reading
        m_rover.readSensors();
        System.out.println("Initial Terrain Boards:");
        this.displayBoards();
        String log = new String();
        int cycles = 0;
        while(!m_inferenceEngine.solved())
        {
            log += m_inferenceEngine.cycle();
            m_rover.readSensors();
            this.displayBoards();
            cycles++;
        }
        System.out.println("Rules fired:");
        System.out.println(log);
        System.out.println("Rover Log:");
        System.out.println(m_database.rover().roverLog());
        System.out.println("Took rover: " + m_database.rover().completedMoves() + " moves");
        if(m_outputFile != null)
        {
            AssignmentFiles outFile = new AssignmentFiles();
            String outString = "Took rover: " + m_database.rover().completedMoves() + " moves\n" + m_database.rover().roverLog() ;
            outString += "\nRules fired:\n"  + log;
            outFile.writeStringToFile(m_outputFile,outString);
        }
    }
    
    private void displayBoards()
    {
        System.out.println("Full Terrain Board");
        m_terrainBoard.showCurrentState();
        System.out.println("Discovered Terrain Board");
        m_discoveredTerrainBoard.showCurrentState();
    }
    public void setup() throws IOException
    {
        this.setRowsColumns();
        this.setupBoards();
        this.setupRover();
        this.setupTarget();
        this.setupDatabase();
        this.setupKnowledgebase();
        this.setupInferenceEngine();
    }
    private void setupTarget() throws IOException
    {
        System.out.println("Please enter the row of the target:");
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        Integer row = new Integer(br.readLine());
        
        System.out.println("Please enter the column of the target:");
        BufferedReader br2 = new BufferedReader(new InputStreamReader(System.in));
        Integer column = new Integer(br2.readLine());
        
        m_terrainBoard.setTarget(row.intValue(),column.intValue());
        m_discoveredTerrainBoard.setTarget(row.intValue(),column.intValue());
    }
    private void setRowsColumns()throws IOException
    {
        m_rows = askRows();
        m_columns = askColumns();
    }
    private void setupDatabase()
    {
        m_database = new Database();
        m_database.rover(m_rover);
        m_database.fullBoard(m_terrainBoard);
        m_database.discoveredBoard(m_discoveredTerrainBoard);
    }
    private void setupKnowledgebase()
    {
        m_knowledgebase = new Knowledgebase();
        m_knowledgebase.setup();
    }
    private void setupInferenceEngine()
    {
        m_inferenceEngine = new InferenceEngine();
        m_inferenceEngine.database(m_database);
        m_inferenceEngine.knowledgebase(m_knowledgebase);        
    }
    private void setupBoards() throws IOException
    {
        m_terrainBoard = new Board(m_rows, m_columns);
        m_terrainBoard.clearBoard();
        m_terrainBoard.setRandomTerrain();

        m_discoveredTerrainBoard = new Board(m_rows, m_columns);   
    }
    private void setupRover() throws IOException
    {
        m_rover = new Rover();
        m_rover.setup();
        m_terrainBoard.rover(m_rover);
        m_discoveredTerrainBoard.rover(m_rover);
        
        m_rover.setFullTerrainBoard(m_terrainBoard);
        m_rover.setDiscoveredBoard(m_discoveredTerrainBoard);
    }
    private int askColumns() throws IOException
    {
        System.out.println("Please input the number of columns:");
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        Integer columns = new Integer(br.readLine());
        return columns.intValue();
    }
    
    private int askRows() throws IOException
    {
        System.out.println("Please input the number of rows:");
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        Integer rows = new Integer(br.readLine());
        return rows.intValue();
    }
}
